#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Maipu AI Coder Enchance 子进程模块
负责处理数据库更新、文件列表生成、ctags和cscope命令执行等功能
"""

import os
import json
import logging
import time
import queue
import subprocess

# 全局常量定义
SUBPROCESS_TIMEOUT = 300  # 子进程执行的默认超时时间（秒）


def run_command_with_timeout(cmd, cwd=None, timeout=SUBPROCESS_TIMEOUT, shell=True, log=None):
    """运行带超时控制的子进程命令
    
    Args:
        cmd: 要执行的命令
        cwd: 工作目录
        timeout: 超时时间（秒）
        shell: 是否使用shell
        log: 可选的日志记录器对象，如果未提供则使用全局logger或创建本地logger
    
    Returns:
        subprocess.CompletedProcess对象
        
    Raises:
        TimeoutError: 当命令执行超时时抛出
        subprocess.SubprocessError: 当命令执行出错时抛出
    """
    # 如果没有提供logger，则尝试使用全局logger或创建本地logger
    local_logger = log

    # 记录开始时间
    start_time = time.time()
    local_logger.info(f"开始执行命令: {cmd}，超时设置为 {timeout} 秒")
    
    try:
        # 使用subprocess.run并设置超时参数
        result = subprocess.run(
            cmd,
            shell=shell,
            cwd=cwd,
            capture_output=True,
            text=True,
            timeout=timeout
        )
        
        duration = time.time() - start_time
        local_logger.info(f"命令执行完成，耗时 {duration:.2f} 秒，返回码: {result.returncode}")
        
        return result
    except subprocess.TimeoutExpired:
        duration = time.time() - start_time
        error_msg = f"命令执行超时: {cmd}，已运行 {duration:.2f} 秒，超过限制 {timeout} 秒"
        local_logger.error(error_msg)
        # raise TimeoutError(error_msg)
    except Exception as e:
        local_logger.error(f"执行命令时发生异常: {str(e)}")
        # raise

def _generate_file_list(source_folders, output_file_path, is_windows):
    """生成文件列表
    
    Args:
        source_folders: 源文件夹列表
        output_file_path: 输出文件路径
        is_windows: 是否为Windows系统
    """
    # 确保输出目录存在
    output_dir = os.path.dirname(output_file_path)
    if output_dir and not os.path.exists(output_dir):
        os.makedirs(output_dir, exist_ok=True)
    
    # 支持的文件扩展名
    supported_extensions = ['.c', '.cpp', '.cc', '.h', '.hpp', '.hh', '.py']
    
    # 创建文件并写入结果
    with open(output_file_path, 'w', encoding='utf-8') as f:
        for folder in source_folders:
            if not os.path.exists(folder):
                continue
            
            # 遍历目录
            for root, _, files in os.walk(folder):
                for file in files:
                    # 检查文件扩展名
                    _, ext = os.path.splitext(file)
                    if ext.lower() in supported_extensions:
                        file_path = os.path.join(root, file)
                        # 根据操作系统调整路径格式
                        if is_windows:
                            # Windows路径直接使用
                            f.write(file_path + '\n')
                        else:
                            # 非Windows路径转换为Unix格式
                            unix_path = file_path.replace('\\', '/')
                            f.write(unix_path + '\n')

def _execute_ctags(source_folders, ctags_path, output_path, workspace_dir, logger):
    """执行ctags命令生成tags文件
    
    Args:
        source_folders: 源文件夹列表
        ctags_path: ctags工具路径
        output_path: 输出文件路径
        workspace_dir: 工作目录
    """
    # 确保输出目录存在
    output_dir = os.path.dirname(output_path)
    if output_dir and not os.path.exists(output_dir):
        os.makedirs(output_dir, exist_ok=True)
    
    # 构建ctags命令
    cmd = f'{ctags_path} -R --sort=yes --fields=* --extras=* --languages=C --languages=+C++ --languages=+Python'

    # 指定输出文件
    cmd += f' -f "{output_path}"'

    # 添加源文件夹
    for folder in source_folders:
        if os.path.exists(folder):
            cmd += f' "{folder}"'
    
    # 执行命令
    run_command_with_timeout(cmd, cwd=workspace_dir, log=logger)

def _execute_cscope(cscope_out_path, cscope_files_path, cscope_path, workspace_dir, logger):
    """执行cscope命令生成cscope数据库
    
    Args:
        cscope_out_path: cscope数据库输出路径
        cscope_files_path: 包含源文件列表的文件路径
        cscope_path: cscope工具路径
        workspace_dir: 工作目录
    """
    # 确保输出目录存在
    output_dir = os.path.dirname(cscope_out_path)
    if output_dir and not os.path.exists(output_dir):
        os.makedirs(output_dir, exist_ok=True)
    
    # 构建cscope命令
    cmd = f'{cscope_path} -bqk -i "{cscope_files_path}" -f "{cscope_out_path}"'
    
    # 执行命令
    run_command_with_timeout(cmd, cwd=workspace_dir, log=logger)

def update_worker(workspace_file, workspace_dir, workspace_basename, tags_out_path, cscope_files_path, cscope_out_path, 
                  readtags_path, ctags_path, cscope_path, 
                  command_queue, status_queue, stop_event, is_windows_param):
    """数据库更新工作进程的主函数"""
    # 初始化worker环境
    worker_logger = logging.getLogger('maipu_ai_coder.worker')
    handler = logging.FileHandler(os.path.join(workspace_dir, f'{workspace_basename}-update_worker.log'), mode='a', encoding='utf-8')
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    worker_logger.addHandler(handler)
    worker_logger.setLevel(logging.INFO)

    worker_logger.info(f"数据库更新进程启动，进程ID: {os.getpid()}，参数检查 - workspace_dir: {workspace_dir}, cscope_files_path: {cscope_files_path}")
    worker_logger.info(f"is_windows_param值: {is_windows_param}")
    
    # 检查参数是否有效
    if not workspace_dir or not os.path.exists(workspace_dir):
        worker_logger.error(f"工作目录不存在或无效: {workspace_dir}")
    if cscope_files_path:
        cscope_dir = os.path.dirname(cscope_files_path)
        worker_logger.info(f"cscope_files_path目录: {cscope_dir}")
        if cscope_dir and not os.path.exists(cscope_dir):
            worker_logger.error(f"cscope_files_path目录不存在: {cscope_dir}")
    
    while not stop_event.is_set():
        try:
            # 尝试从队列获取命令，设置超时以便定期检查停止事件
            try:
                command = command_queue.get(timeout=1)  # 每秒检查一次停止事件
            except queue.Empty:
                continue
                
            if command['type'] == 'update':
                worker_logger.info(f"开始执行{'手动' if command['manual'] else '自动'}更新")
                status_queue.put({'type': 'status', 'is_updating': True, 'progress': 0, 'status': 'starting'})
                
                try:
                    # 1. 读取工作区目录
                    if workspace_file and workspace_file != '.':
                        # 同步读取工作区文件（在worker进程中）
                        source_folders = []
                        if os.path.exists(workspace_file):
                            try:
                                with open(workspace_file, 'r', encoding='utf-8') as f:
                                    workspace_data = json.load(f)
                                
                                if 'folders' in workspace_data:
                                    workspace_dir_worker = os.path.dirname(workspace_file)
                                    
                                    for folder in workspace_data['folders']:
                                        if 'path' in folder:
                                            folder_path = folder['path']
                                            if not os.path.isabs(folder_path):
                                                folder_path = os.path.join(workspace_dir_worker, folder_path)
                                            
                                            folder_path = os.path.normpath(folder_path)
                                            
                                            if os.path.exists(folder_path) and os.path.isdir(folder_path):
                                                source_folders.append(folder_path)
                            except Exception as e:
                                worker_logger.error(f"读取VSCode工作区文件时出错: {str(e)}")
                    
                    # 2. 生成文件列表
                    status_queue.put({'type': 'status', 'progress': 20, 'status': 'generating_file_list'})
                    _generate_file_list(source_folders, cscope_files_path, is_windows_param)
                    
                    # 3. 执行ctags命令
                    status_queue.put({'type': 'status', 'progress': 40, 'status': 'running_ctags'})
                    _execute_ctags(source_folders, ctags_path, tags_out_path, workspace_dir, worker_logger)
                    
                    # 4. 执行cscope命令
                    status_queue.put({'type': 'status', 'progress': 70, 'status': 'running_cscope'})
                    _execute_cscope(cscope_out_path, cscope_files_path, cscope_path, workspace_dir, worker_logger)
                    
                    status_queue.put({'type': 'status', 'progress': 100, 'status': 'completed', 
                                     'last_update_time': time.time()})
                    worker_logger.info(f"{'手动' if command['manual'] else '自动'}更新成功完成")
                except Exception as e:
                    error_msg = str(e)
                    worker_logger.error(f"更新过程中发生错误: {error_msg}")
                    status_queue.put({'type': 'error', 'error': error_msg, 'is_updating': False})
                
                
            elif command['type'] == 'stop':
                worker_logger.info("接收到停止命令，退出工作进程")
                status_queue.put({'type': 'status', 'is_updating': False, 'status': 'stopped'})
                break
                
        except Exception as e:
            worker_logger.error(f"工作进程发生未预期的异常: {str(e)}")
            status_queue.put({'type': 'error', 'error': str(e), 'is_updating': False})
    
    worker_logger.info("工作进程已退出")

if __name__ == '__main__':
    # 当作为独立脚本运行时，这里可以添加测试代码
    pass